package com.android.library.image;

import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;

import androidx.annotation.NonNull;

import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;

import java.security.MessageDigest;

/**
 * @author xiaoxing
 * Glide圆角处理：
 * 1、支持一个圆角、两个圆角，四个圆角
 * 2、支持为每个圆角设置不同圆角半径
 * 备注：可扩展3个圆角，原理相同
 */
public class RoundTransform extends CenterCrop {

    private float mLeftTopRadius;
    private float mRightTopRadius;
    private float mLeftBottomRadius;
    private float mRightBottomRadius;
    private CornerType mCornerType;

    public RoundTransform(CornerType type, float leftTopRadius, float rightTopRadius, float leftBottomRadius, float rightBottomRadius) {
        mCornerType = type;
        mLeftTopRadius = leftTopRadius;
        mRightTopRadius = rightTopRadius;
        mLeftBottomRadius = leftBottomRadius;
        mRightBottomRadius = rightBottomRadius;
    }

    public enum CornerType {
        /**
         * 所有角
         */
        ALL,
        /**
         * 左上角
         */
        LEFT_TOP,
        /**
         * 右上角
         */
        RIGHT_TOP,
        /**
         * 左下角
         */
        LEFT_BOTTOM,
        /**
         * 右下角
         */
        RIGHT_BOTTOM,
        /**
         * 左边
         */
        LEFT,
        /**
         * 右边
         */
        RIGHT,
        /**
         * 上边
         */
        TOP,
        /**
         * 下边
         */
        BOTTOM,
        /**
         * 左上和右下角
         */
        LEFT_TOP_AND_RIGHT_BOTTOM,
        /**
         * 左下和右上角
         */
        LEFT_BOTTOM_AND_RIGHT_TOP
    }

    @Override
    protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
        Bitmap transform = super.transform(pool, toTransform, outWidth, outHeight);
        return roundCrop(pool, transform);
    }

    private Bitmap roundCrop(BitmapPool pool, Bitmap source) {
        if (source == null) {
            return null;
        }

        int width = source.getWidth();
        int height = source.getHeight();

        // 从BitmapPool获取给定配置只包含透明像素的Bitmap，结果返回可能为Null
        Bitmap result = pool.get(width, height, Bitmap.Config.ARGB_8888);
        if (result == null) {
            result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        }

        // 通过Shader画显示区域
        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
        drawRoundCorner(canvas, paint, width, height);
        return result;
    }

    private void drawRoundCorner(Canvas canvas, Paint paint, int width, int height) {
        switch (mCornerType) {
            case LEFT_TOP:
                drawLeftTopCorner(canvas, paint, width, height);
                break;
            case RIGHT_TOP:
                drawRightTopCorner(canvas, paint, width, height);
                break;
            case LEFT_BOTTOM:
                drawLeftBottomCorner(canvas, paint, width, height);
                break;
            case RIGHT_BOTTOM:
                drawRightBottomCorner(canvas, paint, width, height);
                break;
            case LEFT:
                drawLeftCorner(canvas, paint, width, height);
                break;
            case RIGHT:
                drawRightCorner(canvas, paint, width, height);
                break;
            case TOP:
                drawTopCorner(canvas, paint, width, height);
                break;
            case BOTTOM:
                drawBottomCorner(canvas, paint, width, height);
                break;
            case LEFT_TOP_AND_RIGHT_BOTTOM:
                drawLeftTopAndRightBottomCorner(canvas, paint, width, height);
                break;
            case LEFT_BOTTOM_AND_RIGHT_TOP:
                drawLeftBottomAndRightTopCorner(canvas, paint, width, height);
                break;
            case ALL:
            default:
                drawAllCorner(canvas, paint, width, height);
                break;
        }
    }

    private void drawLeftTopCorner(Canvas canvas, Paint paint, int width, int height) {
        canvas.drawRect(new RectF(mLeftTopRadius, 0, width, height), paint);
        canvas.drawRect(new RectF(0, mLeftTopRadius, width, height), paint);
        drawLeftTopArc(canvas, paint, width, height);
    }

    private void drawRightTopCorner(Canvas canvas, Paint paint, int width, int height) {
        canvas.drawRect(new RectF(0, 0, width - mRightTopRadius, height), paint);
        canvas.drawRect(new RectF(width - mRightTopRadius, mRightTopRadius, width, height), paint);
        drawRightTopArc(canvas, paint, width, height);
    }

    private void drawLeftBottomCorner(Canvas canvas, Paint paint, int width, int height) {
        canvas.drawRect(new RectF(0, 0, width, height - mLeftBottomRadius), paint);
        canvas.drawRect(new RectF(mLeftBottomRadius, height - mLeftBottomRadius, width, height), paint);
        drawLeftBottomArc(canvas, paint, width, height);
    }

    private void drawRightBottomCorner(Canvas canvas, Paint paint, int width, int height) {
        canvas.drawRect(new RectF(0, 0, width - mRightBottomRadius, height), paint);
        canvas.drawRect(new RectF(width - mRightBottomRadius, 0, width, height - mRightBottomRadius), paint);
        drawRightBottomArc(canvas, paint, width, height);
    }

    private void drawLeftCorner(Canvas canvas, Paint paint, int width, int height) {
        canvas.drawRect(new RectF(mLeftTopRadius, 0, width, mLeftTopRadius), paint);
        canvas.drawRect(new RectF(0, mLeftTopRadius, width, height - mLeftBottomRadius), paint);
        canvas.drawRect(new RectF(mLeftBottomRadius, height - mLeftBottomRadius, width, height), paint);
        drawLeftTopArc(canvas, paint, width, height);
        drawLeftBottomArc(canvas, paint, width, height);
    }

    private void drawRightCorner(Canvas canvas, Paint paint, int width, int height) {
        canvas.drawRect(new RectF(0, 0, width - mRightTopRadius, mRightTopRadius), paint);
        canvas.drawRect(new RectF(0, mRightTopRadius, width, height - mRightBottomRadius), paint);
        canvas.drawRect(new RectF(0, mRightBottomRadius, width - mRightTopRadius, height), paint);
        drawRightTopArc(canvas, paint, width, height);
        drawRightBottomArc(canvas, paint, width, height);
    }

    private void drawTopCorner(Canvas canvas, Paint paint, int width, int height) {
        canvas.drawRect(new RectF(0, mLeftTopRadius, mLeftTopRadius, height), paint);
        canvas.drawRect(new RectF(mLeftTopRadius, 0, width - mRightTopRadius, height), paint);
        canvas.drawRect(new RectF(width - mRightTopRadius, mRightTopRadius, width, height), paint);
        drawLeftTopArc(canvas, paint, width, height);
        drawRightTopArc(canvas, paint, width, height);
    }

    private void drawBottomCorner(Canvas canvas, Paint paint, int width, int height) {
        canvas.drawRect(new RectF(0, 0, mLeftBottomRadius, height - mLeftBottomRadius), paint);
        canvas.drawRect(new RectF(mLeftBottomRadius, 0, width - mRightBottomRadius, height), paint);
        canvas.drawRect(new RectF(width - mRightBottomRadius, 0, width, height - mRightBottomRadius), paint);
        drawLeftBottomArc(canvas, paint, width, height);
        drawRightBottomArc(canvas, paint, width, height);
    }

    private void drawLeftTopAndRightBottomCorner(Canvas canvas, Paint paint, int width, int height) {
        canvas.drawRect(new RectF(0, mLeftTopRadius, mLeftTopRadius, height), paint);
        canvas.drawRect(new RectF(mLeftTopRadius, 0, width - mRightBottomRadius, height), paint);
        canvas.drawRect(new RectF(width - mRightBottomRadius, 0, width, height - mRightBottomRadius), paint);
        drawLeftTopArc(canvas, paint, width, height);
        drawRightBottomArc(canvas, paint, width, height);
    }

    private void drawLeftBottomAndRightTopCorner(Canvas canvas, Paint paint, int width, int height) {
        canvas.drawRect(new RectF(0, 0, mLeftBottomRadius, height - mLeftBottomRadius), paint);
        canvas.drawRect(new RectF(mLeftBottomRadius, 0, width - mRightTopRadius, height), paint);
        canvas.drawRect(new RectF(width - mRightTopRadius, mRightTopRadius, width, height), paint);
        drawLeftBottomArc(canvas, paint, width, height);
        drawRightTopArc(canvas, paint, width, height);
    }

    private void drawAllCorner(Canvas canvas, Paint paint, int width, int height) {
        float leftMin = Math.min(mLeftTopRadius, mLeftBottomRadius);
        float leftMax = Math.max(mLeftTopRadius, mLeftBottomRadius);
        float rightMin = Math.min(mRightTopRadius, mRightBottomRadius);
        float rightMax = Math.max(mRightTopRadius, mRightBottomRadius);

        canvas.drawRect(new RectF(0, mLeftTopRadius, leftMin, height - mLeftBottomRadius), paint);
        if (mLeftTopRadius > mLeftBottomRadius) {
            canvas.drawRect(new RectF(mLeftBottomRadius, mLeftTopRadius, mLeftTopRadius, height), paint);
        } else {
            canvas.drawRect(new RectF(mLeftTopRadius, 0, mLeftBottomRadius, height - mLeftBottomRadius), paint);
        }
        if (mRightTopRadius > mRightBottomRadius) {
            canvas.drawRect(new RectF(width - mRightTopRadius, mRightTopRadius, width - mRightBottomRadius, height), paint);
        } else {
            canvas.drawRect(new RectF(width - mRightBottomRadius, 0, width - mRightTopRadius, height - mRightBottomRadius), paint);
        }
        canvas.drawRect(new RectF(leftMax, 0, width - rightMax, height), paint);
        canvas.drawRect(new RectF(width - rightMin, mRightTopRadius, width, height - mRightBottomRadius), paint);

        drawLeftTopArc(canvas, paint, width, height);
        drawLeftBottomArc(canvas, paint, width, height);
        drawRightTopArc(canvas, paint, width, height);
        drawRightBottomArc(canvas, paint, width, height);
    }

    /**
     * 画左上角扇形区域
     */
    private void drawLeftTopArc(Canvas canvas, Paint paint, int width, int height) {
        RectF leftTopRectF = new RectF(0, 0, mLeftTopRadius * 2, mLeftTopRadius * 2);
        canvas.drawArc(leftTopRectF, 180, 90, true, paint);
    }

    /**
     * 画右上角扇形区域
     */
    private void drawRightTopArc(Canvas canvas, Paint paint, int width, int height) {
        RectF rightTopRectF = new RectF(width - 2 * mRightTopRadius, 0, width, mRightTopRadius * 2);
        canvas.drawArc(rightTopRectF, 270, 90, true, paint);
    }

    /**
     * 画左下角扇形区域
     */
    private void drawLeftBottomArc(Canvas canvas, Paint paint, int width, int height) {
        RectF leftBottomRectF = new RectF(0, height - 2 * mLeftBottomRadius, 2 * mLeftBottomRadius, height);
        canvas.drawArc(leftBottomRectF, 90, 90, true, paint);
    }

    /**
     * 画右下角扇形区域
     */
    private void drawRightBottomArc(Canvas canvas, Paint paint, int width, int height) {
        RectF rightBottomRectF = new RectF(width - 2 * mRightBottomRadius, height - 2 * mRightBottomRadius, width, height);
        canvas.drawArc(rightBottomRectF, 0, 90, true, paint);
    }

    @Override
    public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {

    }
}
